#!/usr/bin/env python
# coding: utf-8
import pymongo
import logging
from pymongo import errors
from config.config import configs
from middlewares import typeassert


class MongodbUtils(object):
    """
    Mongodb 工具类
    """

    conf = configs["mongo"]

    @classmethod
    def conn(cls):
        """
        connect to mongodb
        :return:
        """

        db = None
        try:
            db = pymongo.MongoClient(cls.conf["mongodb_uri"], appname='european')[cls.conf["mongodb_db"]]
        except pymongo.errors.OperationFailure as ex:
            logging.error('database connect refuse. reason: {0}.'.format(ex))
        finally:
            return db

    @classmethod
    @typeassert(table=str, records=list, primary=tuple)
    def insert_records(cls, table, records, primary=()):
        """
        数据存入Mongodb
        :param table:
        :param records:
        :param primary: primary keys
        :return:
        """

        db = cls.conn()
        if not db:
            return

        try:
            for index, record in enumerate(records):
                find_record = cls.find_record(table, record, primary)
                if find_record:
                    cls.update_record(table, record, {'_id': find_record['_id']})
                else:
                    db[table].insert(record)
        except errors as ex:
            logging.error("The table {0} insert&update is error: {1}.".format(table, ex))

    @classmethod
    @typeassert(table=str, record=dict, primary=tuple)
    def find_record(cls, table, record, primary=()):
        """
        find single record in mongodb
        :param table:
        :param record:
        :param primary:
        :return:
        """

        db = cls.conn()
        if not db:
            return

        condition = {}
        for key in primary:
            condition[key] = record[key]
        find_record = db[table].find(condition)

        result = None
        if find_record.count():
            result = find_record[0]
        return result

    @classmethod
    @typeassert(table=str, record=dict, condition=dict)
    def update_record(cls, table, record, condition={'_id': None}):
        """
        update single record in mongodb
        :param table:
        :param record:
        :param condition:
        :return:
        """

        db = cls.conn()
        if not db:
            return

        condition_value = {}
        for key, value in record.iteritems():
            condition_value[key] = value
        try:
            db[table].update(condition, {"$set": condition_value}, False, True)
        except errors as ex:
            logging.error("The table {0} update is error: {1}.".format(table, ex))

    @classmethod
    @typeassert(table=str, record=dict)
    def delete_record(cls, table, record):
        """
        delete single record in mongodb
        :param table:
        :param record:
        :return:
        """

        db = cls.conn()
        if not db:
            return
        try:
            db[table].remove({"_id": record["_id"]}, multi=False)
        except errors as ex:
            logging.error("The table {0} update is error: {1}.".format(table, ex))

    @classmethod
    @typeassert(table=str, condition=dict)
    def get_records(cls, table, condition):
        """
        find records in table
        :param table:
        :param condition:
        :return:
        """

        db = cls.conn()
        if not db:
            return

        results_list = list()
        try:
            results = db[table].find(condition)
            if results.count():
                for index, row in enumerate(results):
                    results_list.append(row)
            else:
                logging.warning('{0}, no data found.'.format(table))
        except errors as ex:
            msg = "The table {0} find is error: {1}.".format(table, ex)
            logging.error(msg)
        return results_list

    @classmethod
    @typeassert(table=str, condition=dict, sorted_by=str)
    def get_records_order(cls, table, condition, sorted_by):
        """
        find records order by sorted_by in table
        :param table:
        :param condition:
        :param sorted_by:
        :return:
        """

        db = cls.conn()
        if not db:
            return

        results_list = list()
        try:
            results = db[table].find(condition).sort(sorted_by, pymongo.ASCENDING)
            if results.count():
                for index, row in enumerate(results):
                    results_list.append(row)
            else:
                logging.warning('{0}, no data found.'.format(table))
        except errors as ex:
            logging.error("The table {0} find is error: {1}.".format(table, ex))
        return results_list

    @classmethod
    @typeassert(table=str, key=str)
    def get_distinct_key(cls, table, key):
        """
        get distinct key in mongodb
        :param table:
        :param key:
        :return:
        """

        db = cls.conn()
        if not db:
            return

        results_list = list()
        try:
            results = db[table].distinct(key)
            if results:
                for index, row in enumerate(results):
                    results_list.append(row)
            else:
                logging.warning('{0}, key: {1}, no data found.'.format(table, key))
        except errors as ex:
            logging.error("The table {0} find is error: {1}.".format(table, ex))
        return results_list
